home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 2 / AACD 2.iso / AACD / Magazine / GraphicsCards / StormMesa / src-glu / tess.c < prev    next >
C/C++ Source or Header  |  1998-12-15  |  10KB  |  392 lines

  1. /* $Id: tess.c,v 1.9 1998/06/01 01:10:29 brianp Exp $ */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  2.6
  6.  * Copyright (C) 1995-1997  Brian Paul
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Library General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2 of the License, or (at your option) any later version.
  12.  *
  13.  * This library is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Library General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Library General Public
  19.  * License along with this library; if not, write to the Free
  20.  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  */
  22.  
  23.  
  24. /*
  25.  * $Log: tess.c,v $
  26.  * Revision 1.9  1998/06/01 01:10:29  brianp
  27.  * small update for Next/OpenStep from Alexander Mai
  28.  *
  29.  * Revision 1.8  1998/02/04 00:27:58  brianp
  30.  * cygnus changes from Stephane Rehel
  31.  *
  32.  * Revision 1.7  1998/01/16 03:35:26  brianp
  33.  * fixed Windows compilation warnings (Theodore Jump)
  34.  *
  35.  * Revision 1.6  1997/09/17 01:51:48  brianp
  36.  * changed glu*Callback() functions to match prototype in glu.h
  37.  *
  38.  * Revision 1.5  1997/07/24 01:28:44  brianp
  39.  * changed precompiled header symbol from PCH to PC_HEADER
  40.  *
  41.  * Revision 1.4  1997/05/28 02:29:38  brianp
  42.  * added support for precompiled headers (PCH), inserted APIENTRY keyword
  43.  *
  44.  * Revision 1.3  1996/11/12 01:23:02  brianp
  45.  * added test to prevent free(vertex) when vertex==NULL in delete_contours()
  46.  *
  47.  * Revision 1.2  1996/10/22 22:57:19  brianp
  48.  * better error handling in gluBegin/EndPolygon() from Erich Eder
  49.  *
  50.  * Revision 1.1  1996/09/27 01:19:39  brianp
  51.  * Initial revision
  52.  *
  53.  */
  54.  
  55.  
  56. /*
  57.  * This file is part of the polygon tesselation code contributed by
  58.  * Bogdan Sikorski
  59.  */
  60.  
  61.  
  62. #ifdef PC_HEADER
  63. #include "all.h"
  64. #else
  65. #include <math.h>
  66. #include <stdlib.h>
  67. #include "tess.h"
  68. #endif
  69.  
  70. /*
  71.  * This is ugly, but seems the easiest way to do things to make the
  72.  * code work under YellowBox for Windows
  73.  */
  74. #if defined(OPENSTEP) && defined(CALLBACK)
  75. #undef CALLBACK
  76. #define CALLBACK
  77. #endif
  78.  
  79.  
  80. extern void tess_test_polygon(GLUtriangulatorObj *);
  81. extern void tess_find_contour_hierarchies(GLUtriangulatorObj *);
  82. extern void tess_handle_holes(GLUtriangulatorObj *);
  83. extern void tess_tesselate(GLUtriangulatorObj *);
  84. extern void tess_tesselate_with_edge_flag(GLUtriangulatorObj *);
  85. static void delete_contours(GLUtriangulatorObj *);
  86.  
  87. #ifdef __CYGWIN32__
  88. #define _CALLBACK
  89. #else
  90. #define _CALLBACK CALLBACK
  91. #endif
  92.  
  93. void init_callbacks(tess_callbacks *callbacks)
  94. {
  95.    callbacks->begin = ( void (_CALLBACK*)(GLenum) ) 0;
  96.    callbacks->edgeFlag = ( void (_CALLBACK*)(GLboolean) ) 0;
  97.    callbacks->vertex = ( void (_CALLBACK*)(void*) ) 0;
  98.    callbacks->end = ( void (_CALLBACK*)(void) ) 0;
  99.    callbacks->error = ( void (_CALLBACK*)(GLenum) ) 0;
  100. }
  101.  
  102. void tess_call_user_error(GLUtriangulatorObj *tobj,
  103.     GLenum gluerr)
  104. {
  105.     if(tobj->error==GLU_NO_ERROR)
  106.         tobj->error=gluerr;
  107.     if(tobj->callbacks.error!=NULL)
  108.     {
  109. #if defined(AMIGA) && defined(__PPC__)
  110.         currentCallback = (void *)tobj->callbacks.error;
  111.         (tobj->callbacks.errorPPC)(gluerr);
  112. #else
  113.         (tobj->callbacks.error)(gluerr);
  114. #endif
  115.     }
  116. }
  117.  
  118. GLUtriangulatorObj* APIENTRY gluNewTess( void )
  119. {
  120.    GLUtriangulatorObj *tobj;
  121.  
  122.     if((tobj=(GLUtriangulatorObj *)
  123.         malloc(sizeof(struct GLUtriangulatorObj)))==NULL)
  124.         return NULL;
  125.     tobj->contours=tobj->last_contour=NULL;
  126.     init_callbacks(&tobj->callbacks);
  127.     tobj->error=GLU_NO_ERROR;
  128.     tobj->current_polygon=NULL;
  129.     tobj->contour_cnt=0;
  130.     return tobj;
  131. }
  132.  
  133.  
  134. void APIENTRY gluTessCallback( GLUtriangulatorObj *tobj, GLenum which,
  135.                    void (CALLBACK *fn)() )
  136. {
  137.     switch(which)
  138.     {
  139. #if !defined(AMIGA) || (defined(AMIGA) && !defined(__PPC__))
  140.         case GLU_BEGIN:
  141.             tobj->callbacks.begin = (void (_CALLBACK*)(GLenum)) fn;
  142.             break;
  143.         case GLU_EDGE_FLAG:
  144.             tobj->callbacks.edgeFlag = (void (_CALLBACK*)(GLboolean)) fn;
  145.             break;
  146.         case GLU_VERTEX:
  147.             tobj->callbacks.vertex = (void (_CALLBACK*)(void *)) fn;
  148.             break;
  149.         case GLU_END:
  150.             tobj->callbacks.end = (void (_CALLBACK*)(void)) fn;
  151.             break;
  152.         case GLU_ERROR:
  153.             tobj->callbacks.error = (void (_CALLBACK*)(GLenum)) fn;
  154.             break;
  155. #else
  156.         case GLU_BEGIN:
  157.             tobj->callbacks.beginPPC = (void (_CALLBACK*)(GLenum)) beginPPC;
  158.             tobj->callbacks.begin = (void (_CALLBACK*)(GLenum)) fn;
  159.             break;
  160.         case GLU_EDGE_FLAG:
  161.             tobj->callbacks.edgeFlagPPC = (void (_CALLBACK*)(GLboolean)) edgeFlagPPC;
  162.             tobj->callbacks.edgeFlag = (void (_CALLBACK*)(GLboolean)) fn;
  163.             break;
  164.         case GLU_VERTEX:
  165.             tobj->callbacks.vertexPPC = (void (_CALLBACK*)(void *)) vertexPPC;
  166.             tobj->callbacks.vertex = (void (_CALLBACK*)(void *)) fn;
  167.             break;
  168.         case GLU_END:
  169.             tobj->callbacks.endPPC = (void (_CALLBACK*)(void)) endPPC;
  170.             tobj->callbacks.end = (void (_CALLBACK*)(void)) fn;
  171.             break;
  172.         case GLU_ERROR:
  173.             tobj->callbacks.errorPPC = (void (_CALLBACK*)(GLenum)) errorPPC;
  174.             tobj->callbacks.error = (void (_CALLBACK*)(GLenum)) fn;
  175.             break;
  176. #endif
  177.         default:
  178.             tobj->error=GLU_INVALID_ENUM;
  179.             break;
  180.     }
  181. }
  182.  
  183.  
  184.  
  185. void APIENTRY gluDeleteTess( GLUtriangulatorObj *tobj )
  186. {
  187.     if(tobj->error==GLU_NO_ERROR && tobj->contour_cnt)
  188.         /* was gluEndPolygon called? */
  189.         tess_call_user_error(tobj,GLU_TESS_ERROR1);
  190.     /* delete all internal structures */
  191.     delete_contours(tobj);
  192.     free(tobj);
  193. }
  194.  
  195.  
  196. void APIENTRY gluBeginPolygon( GLUtriangulatorObj *tobj )
  197. {
  198. /*
  199.     if(tobj->error!=GLU_NO_ERROR)
  200.         return;
  201. */
  202.     tobj->error = GLU_NO_ERROR;
  203.     if(tobj->current_polygon!=NULL)
  204.     {
  205.         /* gluEndPolygon was not called */
  206.         tess_call_user_error(tobj,GLU_TESS_ERROR1);
  207.         /* delete all internal structures */
  208.         delete_contours(tobj);
  209.     }
  210.     else
  211.     {
  212.         if((tobj->current_polygon=
  213.             (tess_polygon *)malloc(sizeof(tess_polygon)))==NULL)
  214.         {
  215.             tess_call_user_error(tobj,GLU_OUT_OF_MEMORY);
  216.             return;
  217.         }
  218.         tobj->current_polygon->vertex_cnt=0;
  219.         tobj->current_polygon->vertices=
  220.             tobj->current_polygon->last_vertex=NULL;
  221.     }
  222. }
  223.  
  224.  
  225. void APIENTRY gluEndPolygon( GLUtriangulatorObj *tobj )
  226. {
  227.     /*tess_contour *contour_ptr;*/
  228.  
  229.     /* there was an error */
  230.     if(tobj->error!=GLU_NO_ERROR) goto end;
  231.  
  232.     /* check if gluBeginPolygon was called */
  233.     if(tobj->current_polygon==NULL)
  234.     {
  235.         tess_call_user_error(tobj,GLU_TESS_ERROR2);
  236.         return;
  237.     }
  238.     tess_test_polygon(tobj);
  239.     /* there was an error */
  240.     if(tobj->error!=GLU_NO_ERROR) goto end;
  241.  
  242.     /* any real contours? */
  243.     if(tobj->contour_cnt==0)
  244.     {
  245.         /* delete all internal structures */
  246.         delete_contours(tobj);
  247.         return;
  248.     }
  249.     tess_find_contour_hierarchies(tobj);
  250.     /* there was an error */
  251.     if(tobj->error!=GLU_NO_ERROR) goto end;
  252.  
  253.     tess_handle_holes(tobj);
  254.     /* there was an error */
  255.     if(tobj->error!=GLU_NO_ERROR) goto end;
  256.  
  257.     /* if no callbacks, nothing to do */
  258.     if(tobj->callbacks.begin!=NULL && tobj->callbacks.vertex!=NULL &&
  259.         tobj->callbacks.end!=NULL)
  260.     {
  261.         if(tobj->callbacks.edgeFlag==NULL)
  262.             tess_tesselate(tobj);
  263.         else
  264.             tess_tesselate_with_edge_flag(tobj);
  265.     }
  266.  
  267. end:
  268.     /* delete all internal structures */
  269.     delete_contours(tobj);
  270. }
  271.  
  272.  
  273. void APIENTRY gluNextContour( GLUtriangulatorObj *tobj, GLenum type )
  274. {
  275.     if(tobj->error!=GLU_NO_ERROR)
  276.         return;
  277.     if(tobj->current_polygon==NULL)
  278.     {
  279.         tess_call_user_error(tobj,GLU_TESS_ERROR2);
  280.         return;
  281.     }
  282.     /* first contour? */
  283.     if(tobj->current_polygon->vertex_cnt)
  284.         tess_test_polygon(tobj);
  285. }
  286.  
  287.  
  288. void APIENTRY gluTessVertex( GLUtriangulatorObj *tobj, GLdouble v[3], void *data )
  289. {
  290.     tess_polygon *polygon=tobj->current_polygon;
  291.     tess_vertex *last_vertex_ptr;
  292.  
  293.     if(tobj->error!=GLU_NO_ERROR)
  294.         return;
  295.     if(polygon==NULL)
  296.     {
  297.         tess_call_user_error(tobj,GLU_TESS_ERROR2);
  298.         return;
  299.     }
  300.     last_vertex_ptr=polygon->last_vertex;
  301.     if(last_vertex_ptr==NULL)
  302.     {
  303.         if((last_vertex_ptr=(tess_vertex *)
  304.             malloc(sizeof(tess_vertex)))==NULL)
  305.         {
  306.             tess_call_user_error(tobj,GLU_OUT_OF_MEMORY);
  307.             return;
  308.         }
  309.         polygon->vertices=last_vertex_ptr;
  310.         polygon->last_vertex=last_vertex_ptr;
  311.         last_vertex_ptr->data=data;
  312.         last_vertex_ptr->location[0]=v[0];
  313.         last_vertex_ptr->location[1]=v[1];
  314.         last_vertex_ptr->location[2]=v[2];
  315.         last_vertex_ptr->next=NULL;
  316.         last_vertex_ptr->previous=NULL;
  317.         ++(polygon->vertex_cnt);
  318.     }
  319.     else
  320.     {
  321.         tess_vertex *vertex_ptr;
  322.  
  323.         /* same point twice? */
  324.         if(fabs(last_vertex_ptr->location[0]-v[0]) < EPSILON &&
  325.             fabs(last_vertex_ptr->location[1]-v[1]) < EPSILON &&
  326.             fabs(last_vertex_ptr->location[2]-v[2]) < EPSILON)
  327.         {
  328.             tess_call_user_error(tobj,GLU_TESS_ERROR6);
  329.             return;
  330.         }
  331.         if((vertex_ptr=(tess_vertex *)
  332.             malloc(sizeof(tess_vertex)))==NULL)
  333.         {
  334.             tess_call_user_error(tobj,GLU_OUT_OF_MEMORY);
  335.             return;
  336.         }
  337.         vertex_ptr->data=data;
  338.         vertex_ptr->location[0]=v[0];
  339.         vertex_ptr->location[1]=v[1];
  340.         vertex_ptr->location[2]=v[2];
  341.         vertex_ptr->next=NULL;
  342.         vertex_ptr->previous=last_vertex_ptr;
  343.         ++(polygon->vertex_cnt);
  344.         last_vertex_ptr->next=vertex_ptr;
  345.         polygon->last_vertex=vertex_ptr;
  346.     }
  347. }
  348.  
  349.  
  350. static void delete_contours(GLUtriangulatorObj *tobj)
  351. {
  352.     tess_polygon *polygon=tobj->current_polygon;
  353.     tess_contour *contour,*contour_tmp;
  354.     tess_vertex *vertex,*vertex_tmp;
  355.  
  356.     /* remove current_polygon list - if exists due to detected error */
  357.     if(polygon!=NULL)
  358.     {
  359.         if (polygon->vertices)
  360.         {
  361.             for(vertex=polygon->vertices;vertex!=polygon->last_vertex;)
  362.             {
  363.                 vertex_tmp=vertex->next;
  364.                 free(vertex);
  365.                 vertex=vertex_tmp;
  366.             }
  367.             free(vertex);
  368.         }
  369.         free(polygon);
  370.         tobj->current_polygon=NULL;
  371.     }
  372.     /* remove all contour data */
  373.     for(contour=tobj->contours;contour!=NULL;)
  374.     {
  375.         for(vertex=contour->vertices;vertex!=contour->last_vertex;)
  376.         {
  377.             vertex_tmp=vertex->next;
  378.             free(vertex);
  379.             vertex=vertex_tmp;
  380.         }
  381.         free(vertex);
  382.         contour_tmp=contour->next;
  383.         free(contour);
  384.         contour=contour_tmp;
  385.     }
  386.     tobj->contours=tobj->last_contour=NULL;
  387.     tobj->contour_cnt=0;
  388. }
  389.  
  390.  
  391.  
  392.